package com.ease.component.controls.tree {

   import flash.events.MouseEvent;

   import mx.controls.Image;
   import mx.controls.Tree;
   import mx.controls.listClasses.BaseListData;
   import mx.controls.treeClasses.DefaultDataDescriptor;
   import mx.controls.treeClasses.TreeItemRenderer;
   import mx.controls.treeClasses.TreeListData;
   import mx.core.FlexGlobals;
   import mx.core.UIComponent;
   import mx.events.ListEvent;
   import mx.managers.PopUpManager;

   public class CheckboxTreeItemRenderer extends TreeItemRenderer {

      private static const CONTROL_GAP:int = 2;

      /**
       * Default value for placement of icon related to check box.
       */
      private static const ICON_PLACEMENT_AFTER_CHECKBOX:Boolean = true;

      /**
       * The name of the field in the data provider items to determine the placement
       * of icon in this checkbox tree item renderer.
       *
       * @default "true"
       */
      private static const ICON_PLACEMENT_FIELD:String = "placeIconAfterCheckBox";

      //---------------------------------------------------------------------------
      // Constructor

      /** @private */
      public function CheckboxTreeItemRenderer() {
         super();
         this.setStyle("verticalAlign", 'middle');
         this.addEventListener(MouseEvent.MOUSE_MOVE, onMouseOver);
         this.addEventListener(MouseEvent.ROLL_OUT, onMouseOut);
      }

      //---------------------------------------------------------------------------
      // Instance Variables

      /**
       * Owner tree of this checkbox tree item renderer.
       */
      protected var _listOwnerTree:TriStateCheckBoxTree;

      /**
       * TriStateCheckBox reference used in this checkbox tree item renderer.
       */
      private var _checkBox:TriStateCheckBox;

      /**
       * infoIcon
       */
      private var _infoIcon:Image;

      /**
       * Property for optimally updating the changes in the <code>stateField</code>
       * property of this checkbox tree item renderer.
       */
      private var _stateFieldChanged:Boolean;

      /**
       * Property to optimally update changes in the <code>readOnly</code>
       * property of this checkbox tree item renderer.
       */
      private var _readOnlyChanged:Boolean;

      //---------------------------------------------------------------------------
      // Instance Properties

      //-------------------------------------------------------
      // stateField

      private var _stateField:String = "state";

      [Inspectable(type = "String", defaultValue = "state")]

      /**
       * The name of the field in the data provider items to determine the state
       * of <code>TriStateCheckBox</code> in this checkbox tree item renderer.
       *
       * @default "state"
       *
       * @see com.vmware.widgets.controls.TriStateCheckBox
       */
      public function get stateField():String {
         return _stateField;
      }

      /** @private */
      public function set stateField(value:String):void {
         if(_stateField == value){
            return;
         }
         _stateField = value;
         _stateFieldChanged = true;
         invalidateProperties();
      }

      //-------------------------------------------------------
      // readOnly

      private var _readOnly:Boolean;

      /**
       * Represents the read only state of the tri state check box.
       *
       * @see com.vmware.widgets.controls.TriStateCheckBox
       */
      public function get readOnly():Boolean {
         return _readOnly;
      }

      /** @private */
      public function set readOnly(value:Boolean):void {
         if (_readOnly == value) {
            return;
         }
         _readOnly = value;
         _readOnlyChanged = true;
         invalidateProperties();
      }

      //---------------------------------------------------------------------------
      // Overridden Methods

      override public function set listData(value:BaseListData):void {
         super.listData = value;
         if (value && value.owner) {
            value.owner.addEventListener(ListEvent.CHANGE, onSelectItemChanged)
         }
      }

      /**
       * @inheritDoc
       */
      override protected function createChildren():void {
         super.createChildren();

         if (_checkBox == null) {
            _checkBox = new TriStateCheckBox();
            _checkBox.disableTriStatesForUserActions = true;
            _checkBox.addEventListener(MouseEvent.CLICK, onCheckboxClick);

            this.addChild(_checkBox);
         }

         if (_infoIcon == null) {
            _infoIcon = new Image();
//            _infoIcon.source = IconConstant.QUESTION_ICON;
            _infoIcon.addEventListener(MouseEvent.CLICK, onInfoIconClick);
            this.addChild(_infoIcon);
         }
      }

      /**
       * @inheritDoc
       */
      override protected function commitProperties():void {
         super.commitProperties();

         if (this.data != null) {
            _listOwnerTree = (this.listData.owner as TriStateCheckBoxTree);
            var previousState:String = _checkBox.state;
            var currentState:String = itemState();

            if(previousState != currentState){
               _checkBox.state = currentState;
            }

            var dataDescriptor:DefaultDataDescriptor =
               Tree(this.owner).dataDescriptor as DefaultDataDescriptor;

            if (dataDescriptor != null) {
               var enabled:Boolean = dataDescriptor.isEnabled(this.data);
               _checkBox.enabled = enabled;
               this.enabled = enabled;
               _infoIcon.visible = _listOwnerTree.selectedItem == this.data &&
                  !dataDescriptor.isBranch(this.data);
            }
         }

         if (_readOnlyChanged) {
            _checkBox.visible = !_readOnly;
            _readOnlyChanged = false;
         }
      }

      /**
       * @inheritDoc
       */
      override protected function updateDisplayList(unscaledWidth:Number,
                                                    unscaledHeight:Number):void {
         super.updateDisplayList(unscaledWidth, unscaledHeight);

         var startx:Number;
         var verticalAlign:String = this.getStyle("verticalAlign");
         var iconPlacement:Boolean = placeIconAfterCheckBox();

         if(this.icon && iconPlacement == false){
            startx = this.icon.x + this.icon.measuredWidth;
         } else if (this.disclosureIcon != null) {
            startx = this.disclosureIcon.x + this.disclosureIcon.width;
         } else {
            startx = (this.data != null) ? (listData as TreeListData).indent : 0;
         }

         if (_checkBox != null) {
            _checkBox.x = startx + CONTROL_GAP;
            startx = _checkBox.x + _checkBox.measuredWidth;
            _checkBox.setActualSize(_checkBox.measuredWidth, _checkBox.measuredHeight);
         }

         if (this.icon && iconPlacement) {
            icon.x = startx + CONTROL_GAP;
            startx = icon.x + icon.measuredWidth;
         }

         this.label.x = startx + CONTROL_GAP;
         this.label.setActualSize(unscaledWidth - startx, label.measuredHeight);
         startx = label.x + label.measuredWidth;

         if (_infoIcon != null && _infoIcon.visible) {
            _infoIcon.x = startx + CONTROL_GAP;
            _infoIcon.setActualSize(_infoIcon.measuredWidth, _infoIcon.measuredHeight);
         }

         if (verticalAlign == "top") {
            _checkBox.y = 0;
            this.label.y = 0;
         } else if (verticalAlign == "bottom") {
            _checkBox.y = unscaledHeight - _checkBox.height + CONTROL_GAP;
            this.label.y =
               unscaledHeight - this.label.getExplicitOrMeasuredHeight() + CONTROL_GAP;
         } else {
            _checkBox.y = (unscaledHeight - _checkBox.height) / 2;
            this.label.y =
               (unscaledHeight - this.label.getExplicitOrMeasuredHeight()) / 2;
         }

      }

      /**
       * @inheritDoc
       */
      override protected function measure():void {
         super.measure();

         var mw:Number = this.measuredWidth;
         var mh:Number = this.measuredHeight;

         mw += _checkBox.getExplicitOrMeasuredWidth() + CONTROL_GAP;
         mh = Math.max(_checkBox.getExplicitOrMeasuredHeight(), mh);

         this.measuredHeight = mh;
         this.measuredWidth = mw;
      }

      //---------------------------------------------------------------------------
      // Instance Methods

      /**
       * Return boolean flage based on
       * <code>CheckboxTreeItemRenderer.ICON_PLACEMENT_FIELD<code> const.
       * If the function cannot find or convert the parameter to Boolean, it
       * will return CheckboxTreeItemRenderer.STATE_UNCHECKED state.
       */
      private function placeIconAfterCheckBox():Boolean {
         var item:Object = this.data;
         var place:Boolean = ICON_PLACEMENT_AFTER_CHECKBOX;

         if (item == null) {
            return place;
         }

         if (item is XML) {
            if (item[ICON_PLACEMENT_FIELD].length() != 0) {
               var placeStr:String = item[ICON_PLACEMENT_FIELD];
               if(placeStr == "false"){
                  place = false;
               }
            }
         } else if (item is Object) {
            if (item[ICON_PLACEMENT_FIELD] != null) {
               place = item[ICON_PLACEMENT_FIELD];
            }
         }

         return place;
      }

      /**
       * Return state based on <code>stateField<code> property.
       * If the function cannot find or convert the parameter to state string, it
       * will return TriStateCheckBox.STATE_UNCHECKED state.
       */
      private function itemState():String {
         var item:Object = this.data;
         var state:String = TriStateCheckBox.STATE_UNCHECKED;

         if (item == null) {
            return state;
         }

         if (item is XML) {
            if (item[_stateField].length() != 0) {
               state = item[_stateField];
            }
         } else if (item is Object) {
            if (item[_stateField] != null) {
               state = item[_stateField];
            }
         }

         return state;
      }

      /**
       * Updates the state field in the node, the field is determined by
       * <code>stateField</code> property.
       */
      private function updateItemState(state:String):void {
         var item:Object = this.data;

         if (item == null) {
            return;
         }

         if (item is XML) {
            if (item[_stateField].length() != 0) {
               item[_stateField] = state;
            }
         } else if (item is Object) {
            if (item[_stateField] != null) {
               item[_stateField] = state;
            }
         }
      }

      //---------------------------------------------------------------------------
      // Event Handlers

      //-------------------------------------------------------
      // onCheckboxClick

      /**
       * Check box click handler of this tree renderer.
       */
      private function onCheckboxClick(event:MouseEvent):void {
         var state:String = (_checkBox.selected) ? TriStateCheckBox.STATE_CHECKED :
            TriStateCheckBox.STATE_UNCHECKED;

         updateItemState(state);

      }

      private function onInfoIconClick(event:MouseEvent):void {
         _listOwnerTree = (this.listData.owner as TriStateCheckBoxTree);
         var msg:String = this.data[_listOwnerTree.dataTipField];
//         var infoDlg:MoreInfoDialog = PopUpManager.createPopUp(FlexGlobals.topLevelApplication as UIComponent, MoreInfoDialog, true) as MoreInfoDialog;
//         infoDlg.information = msg;
//         infoDlg.height = 180;
//         PopUpManager.centerPopUp(infoDlg);
      }

      private function onSelectItemChanged(event:ListEvent):void {
         invalidateProperties();
      }

      private function onMouseOver(event:MouseEvent):void {
         var dataDescriptor:DefaultDataDescriptor =
            Tree(this.owner).dataDescriptor as DefaultDataDescriptor;

         if (dataDescriptor != null) {
            _infoIcon.visible = !dataDescriptor.isBranch(this.data);
            invalidateDisplayList();
         }
      }

      private function onMouseOut(event:MouseEvent):void {
         invalidateProperties();
      }
   }
}